package com.chenfan.mcn.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.mcn.clients.baseinfo.BaseDicts;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.DictTypeCst;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.constant.SeparatorCst;
import com.chenfan.mcn.dao.StarQuoteWayMapper;
import com.chenfan.mcn.dao.StarRateCardConfigMapper;
import com.chenfan.mcn.dao.StarRateCardDetailMapper;
import com.chenfan.mcn.enums.QuoteDataTypeEnum;
import com.chenfan.mcn.enums.RateCardBasicInfoEnum;
import com.chenfan.mcn.enums.RateCardPlatformInfoEnum;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.common.extension.validation.groups.Add;
import com.chenfan.common.extension.validation.groups.Modify;
import com.chenfan.mcn.model.StarQuoteWay;
import com.chenfan.mcn.model.StarRateCardConfig;
import com.chenfan.mcn.model.StarRateCardDetail;
import com.chenfan.mcn.model.dto.StarQuoteWayDTO;
import com.chenfan.mcn.model.dto.StarRateCardConfigSaveDTO;
import com.chenfan.mcn.model.vo.StarQuoteWayVO;
import com.chenfan.mcn.model.vo.StarRateCardConfigVO;
import com.chenfan.mcn.service.StarRateCardConfigService;
import com.chenfan.mcn.utils.BusinessAssert;
import com.chenfan.mcn.utils.CommonUtil;
import com.chenfan.mcn.utils.ValidatorUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author liuyang
 * @Date 2021/12/29
 * @Time 16:08
 * @Version V1.0
 **/
@Service
public class StarRateCardConfigServiceImpl implements StarRateCardConfigService {

    @Autowired
    private StarRateCardConfigMapper starRateCardConfigMapper;

    @Autowired
    private StarQuoteWayMapper starQuoteWayMapper;

    @Autowired
    private StarRateCardDetailMapper starRateCardDetailMapper;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addStarRateCardConfig(StarRateCardConfigSaveDTO saveDTO) {
        this.verifyQuoteWays(saveDTO.getId(), saveDTO.getStarQuoteWays());
        saveDTO.setId(null);
        saveDTO.getStarQuoteWays().forEach(starQuoteWayDTO -> {
            starQuoteWayDTO.setId(null);
            starQuoteWayDTO.setWayCode(null);
        });
        StarRateCardConfig starRateCardConfig = new StarRateCardConfig();
        BeanUtils.copyProperties(saveDTO, starRateCardConfig);
        //新增不需要做版本控制
        BusinessAssert.isTrue(starRateCardConfigMapper.notExist(Wrappers.lambdaQuery(StarRateCardConfig.class)
                .eq(StarRateCardConfig::getPlatformId, saveDTO.getPlatformId()).eq(StarRateCardConfig::getIsDelete, NumberCst.ZERO)
        ), McnErrorCode.DATA_EXISTED, "配置已存在！刊例平台=" + saveDTO.getPlatformName());
        starRateCardConfig.setId(null);
        starRateCardConfig.setBasicInfo(JSONObject.toJSONString(saveDTO.getBasicInfo()));
        starRateCardConfig.setPlatformInfo(JSONObject.toJSONString(saveDTO.getPlatformInfo()));
        starRateCardConfig.setStatus(NumberCst.ONE);
        starRateCardConfig.setVersion(1L);
        boolean addResult = starRateCardConfigMapper.insert(starRateCardConfig) > 0;
        if (addResult) {
            this.saveStarQuoteWays(starRateCardConfig.getId(), saveDTO.getStarQuoteWays(), null);
        }
        return addResult;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modifyStarRateCardConfig(StarRateCardConfigSaveDTO saveDTO) {
        StarRateCardConfig cardConfig = this.getStarRateCardConfig(saveDTO.getId(), true);
        BusinessAssert.isTrue(NumberCst.ONE.equals(cardConfig.getStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "非启用状态，不允许修改");
        //判断是否存在平台ID变更
        if (!cardConfig.getPlatformId().equals(saveDTO.getPlatformId())) {
            return this.addStarRateCardConfig(saveDTO);
        }
        this.verifyQuoteWays(saveDTO.getId(), saveDTO.getStarQuoteWays());
        boolean existed = starRateCardDetailMapper.exist(Wrappers.lambdaQuery(StarRateCardDetail.class)
                .eq(StarRateCardDetail::getConfigId, cardConfig.getId()).eq(StarRateCardDetail::getIsDelete, NumberCst.ZERO));
        boolean result;
        if (existed) {
            StarRateCardConfig updateEntity = new StarRateCardConfig();
            updateEntity.setId(cardConfig.getId());
            //原数据置为已归档
            updateEntity.setStatus(NumberCst.TWO);
            result = starRateCardConfigMapper.updateById(updateEntity) > 0;
            if (result) {
                //新增一条
                StarRateCardConfig addEntity = new StarRateCardConfig();
                BeanUtils.copyProperties(saveDTO, addEntity);
                addEntity.setId(null);
                addEntity.setBasicInfo(JSONObject.toJSONString(saveDTO.getBasicInfo()));
                addEntity.setPlatformInfo(JSONObject.toJSONString(saveDTO.getPlatformInfo()));
                addEntity.setStatus(NumberCst.ONE);
                addEntity.setVersion(ObjectUtils.defaultIfNull(cardConfig.getVersion(), 1L) + 1L);
                starRateCardConfigMapper.insert(addEntity);
                this.saveStarQuoteWays(addEntity.getId(), saveDTO.getStarQuoteWays(), null);
            }
        } else {
            StarRateCardConfig updateEntity = new StarRateCardConfig();
            BeanUtils.copyProperties(saveDTO, updateEntity);
            updateEntity.setBasicInfo(JSONObject.toJSONString(saveDTO.getBasicInfo()));
            updateEntity.setPlatformInfo(JSONObject.toJSONString(saveDTO.getPlatformInfo()));
            result = starRateCardConfigMapper.updateById(updateEntity) > 0;
            List<StarQuoteWayDTO> starQuoteWays = saveDTO.getStarQuoteWays();
            if (result && !CollectionUtils.isEmpty(starQuoteWays)) {
                List<StarQuoteWayDTO> updateList = starQuoteWays.stream().filter(x -> Objects.nonNull(x.getId())).collect(Collectors.toList());
                List<StarQuoteWayDTO> insertList = starQuoteWays.stream().filter(x -> Objects.isNull(x.getId())).collect(Collectors.toList());
                this.saveStarQuoteWays(cardConfig.getId(), insertList, updateList);
            }
        }
        return result;
    }

    @Override
    public boolean changeStatus(Long id, Integer status) {
        StarRateCardConfig entity = this.getStarRateCardConfig(id, true);
        ;
        StarRateCardConfig updateEntity = new StarRateCardConfig();
        updateEntity.setId(entity.getId());
        updateEntity.setStatus(status);
        return starRateCardConfigMapper.updateById(updateEntity) > 0;
    }

    @Override
    public List<StarRateCardConfig> getNewestConfig() {
        return starRateCardConfigMapper.getNewestConfig(this.getPlatformIds());
    }

    @Override
    public List<StarRateCardConfigVO> getList() {
        List<StarRateCardConfig> list = starRateCardConfigMapper.selectList(Wrappers.lambdaQuery(StarRateCardConfig.class)
                .eq(StarRateCardConfig::getTenantId, UserVoContextHolder.defaultTenantId())
                .in(StarRateCardConfig::getStatus, Arrays.asList(NumberCst.ZERO, NumberCst.ONE))
                .in(StarRateCardConfig::getPlatformId, this.getPlatformIds())
                .eq(StarRateCardConfig::getIsDelete, NumberCst.ZERO)
                .orderByDesc(StarRateCardConfig::getCreateDate));
        //查询所有基础信息
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>(0);
        }
        List<StarRateCardConfigVO> voList = new ArrayList<>(list.size());
        for (StarRateCardConfig config : list) {
            StarRateCardConfigVO configVO = new StarRateCardConfigVO();
            BeanUtils.copyProperties(config, configVO);
            List<String> fieldDescList = new ArrayList<>();
            List<String> basicInfoList = JSONObject.parseObject(configVO.getBasicInfo(), new TypeReference<List<String>>() {
            });
            fieldDescList.addAll(RateCardBasicInfoEnum.getDescList(basicInfoList));
            List<String> platformInfoList = JSONObject.parseObject(configVO.getPlatformInfo(), new TypeReference<List<String>>() {
            });
            fieldDescList.addAll(RateCardPlatformInfoEnum.getDescList(platformInfoList));
            configVO.setBasicInfoDisplay(StringUtils.join(fieldDescList, SeparatorCst.COMMA));
            voList.add(configVO);
        }
        List<Long> configIds = list.stream().map(StarRateCardConfig::getId).distinct().collect(Collectors.toList());
        List<StarQuoteWay> quotWayList = starQuoteWayMapper.selectList(Wrappers.lambdaQuery(StarQuoteWay.class)
                .in(StarQuoteWay::getConfigId, configIds).eq(StarQuoteWay::getIsDelete, NumberCst.ZERO));
        if (CollectionUtils.isNotEmpty(quotWayList)) {
            Map<Long, List<StarQuoteWay>> quotWayMap = quotWayList.stream().collect(Collectors.groupingBy(StarQuoteWay::getConfigId));
            for (StarRateCardConfigVO vo : voList) {
                if (CollectionUtils.isNotEmpty(quotWayMap.get(vo.getId()))) {
                    List<String> wayNameList = quotWayMap.get(vo.getId()).stream().map(StarQuoteWay::getWayName).distinct().collect(Collectors.toList());
                    vo.setQuoteWayDisplay(StringUtils.join(wayNameList, SeparatorCst.COMMA));
                }
            }
        }
        return voList;
    }

    @Override
    public StarRateCardConfigVO detail(Long id) {
        StarRateCardConfig entity = this.getStarRateCardConfig(id, true);
        StarRateCardConfigVO configVO = new StarRateCardConfigVO();
        BeanUtils.copyProperties(entity, configVO);
        List<String> fieldDescList = new ArrayList<>();
        List<String> basicInfoList = JSONObject.parseObject(configVO.getBasicInfo(), new TypeReference<List<String>>() {
        });
        fieldDescList.addAll(RateCardBasicInfoEnum.getDescList(basicInfoList));
        List<String> platformInfoList = JSONObject.parseObject(configVO.getPlatformInfo(), new TypeReference<List<String>>() {
        });
        fieldDescList.addAll(RateCardPlatformInfoEnum.getDescList(platformInfoList));
        configVO.setBasicInfoDisplay(StringUtils.join(fieldDescList, SeparatorCst.COMMA));
        List<StarQuoteWay> quotWayList = starQuoteWayMapper.selectList(Wrappers.lambdaQuery(StarQuoteWay.class)
                .eq(StarQuoteWay::getConfigId, id).eq(StarQuoteWay::getIsDelete, NumberCst.ZERO));
        if (CollectionUtils.isNotEmpty(quotWayList)) {
            List<String> wayNameList = quotWayList.stream().map(StarQuoteWay::getWayName).distinct().collect(Collectors.toList());
            configVO.setQuoteWayDisplay(StringUtils.join(wayNameList, SeparatorCst.COMMA));
            configVO.setQuoteWayList(quotWayList.stream().map(e -> {
                StarQuoteWayVO starQuoteWayVO = new StarQuoteWayVO();
                BeanUtils.copyProperties(e, starQuoteWayVO);
                return starQuoteWayVO;
            }).collect(Collectors.toList()));
            if (CollectionUtils.isNotEmpty(configVO.getQuoteWayList())) {
                Collections.sort(configVO.getQuoteWayList(), (o1, o2) -> o1.getOrderNum().intValue() - o2.getOrderNum().intValue());
            }
        }
        return configVO;
    }

    /**
     * 新增报价方式
     *
     * @param configId
     * @param insertQuoteWays
     * @return
     */
    private void saveStarQuoteWays(Long configId, List<StarQuoteWayDTO> insertQuoteWays, List<StarQuoteWayDTO> updateQuoteWays) {
        //更新或删除
        if (CollectionUtils.isNotEmpty(updateQuoteWays)) {
            List<Long> idList = updateQuoteWays.stream().map(StarQuoteWayDTO::getId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(idList)) {
                starQuoteWayMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarQuoteWay.class)
                        .set(StarQuoteWay::getIsDelete, NumberCst.ONE)
                        .set(StarQuoteWay::getUpdateBy, UserVoContextHolder.getUserId())
                        .set(StarQuoteWay::getUpdateName, UserVoContextHolder.getUserName())
                        .set(StarQuoteWay::getUpdateDate, new Date())
                        .eq(StarQuoteWay::getConfigId, configId)
                        .notIn(StarQuoteWay::getId, idList));
            }
            for (StarQuoteWayDTO item : updateQuoteWays) {
                StarQuoteWay starQuoteWay = new StarQuoteWay();
                BeanUtils.copyProperties(item, starQuoteWay);
                starQuoteWay.setConfigId(configId);
                starQuoteWay.setWayCode(null);
                starQuoteWayMapper.updateById(starQuoteWay);
            }
        }
        //新增
        if (CollectionUtils.isNotEmpty(insertQuoteWays)) {
            List<StarQuoteWay> starQuoteWays = insertQuoteWays.stream().map(item -> {
                StarQuoteWay starQuoteWay = new StarQuoteWay();
                BeanUtils.copyProperties(item, starQuoteWay);
                starQuoteWay.setId(null);
                starQuoteWay.setConfigId(configId);
                if (StringUtils.isBlank(starQuoteWay.getWayCode())) {
                    starQuoteWay.setWayCode(CommonUtil.getShortUuid());
                }
                return starQuoteWay;
            }).collect(Collectors.toList());
            starQuoteWayMapper.insertBatch(starQuoteWays);
        }
    }

    /**
     * 校验报价方式
     *
     * @param starQuoteWays
     */
    private void verifyQuoteWays(Long cardId, List<StarQuoteWayDTO> starQuoteWays) {
//        BusinessAssert.notEmpty(starQuoteWays, McnErrorCode.PARAM_ERROR, " 请至少添加一条报价方式");
        //校验报价方式
        if (CollectionUtils.isNotEmpty(starQuoteWays)) {
            starQuoteWays.forEach(starQuoteWay -> {
                ValidatorUtil.validate(starQuoteWay, Objects.isNull(cardId) ? Add.class : Modify.class);
                QuoteDataTypeEnum quoteDataTypeEnum = QuoteDataTypeEnum.toEnum(starQuoteWay.getDataType());
                BusinessAssert.notNull(quoteDataTypeEnum, McnErrorCode.PARAM_ERROR, "非法数据类型标记！方式名称=" + starQuoteWay.getWayName());
            });
            //校验名称重复
            List<String> wayNameList = starQuoteWays.stream().map(StarQuoteWayDTO::getWayName).collect(Collectors.collectingAndThen(Collectors
                    .groupingBy(Function.identity(), Collectors.counting()), map -> {
                map.values().removeIf(size -> size == 1);
                List<String> tempList = new ArrayList<>(map.keySet());
                return tempList;
            }));
            if (CollectionUtils.isNotEmpty(wayNameList)) {
                String wayNames = StringUtils.join(wayNameList, SeparatorCst.COMMA);
                throw new BusinessException(McnErrorCode.PARAM_ERROR.code(), String.format("【%s】方式名称重复", wayNames));
            }
        }
    }

    /**
     * 根据ID获取刊例配置
     *
     * @param id
     * @return
     */
    @Override
    public StarRateCardConfig getStarRateCardConfig(Long id, boolean verifyExist) {
        StarRateCardConfig starRateCardConfig = starRateCardConfigMapper.selectOne(Wrappers.lambdaQuery(StarRateCardConfig.class)
                .eq(StarRateCardConfig::getId, id).eq(StarRateCardConfig::getIsDelete, NumberCst.ZERO));
        if (verifyExist) {
            BusinessAssert.notNull(starRateCardConfig, McnErrorCode.DATA_NOT_FOUND, "查询不到该刊例配置");
        }
        return starRateCardConfig;
    }

    @Override
    public List<StarQuoteWay> getStarQuoteWays(List<Long> configIds, Integer status) {
        return starQuoteWayMapper.selectList(Wrappers.lambdaQuery(StarQuoteWay.class)
                .in(StarQuoteWay::getConfigId, configIds)
                .eq(Objects.nonNull(status), StarQuoteWay::getStatus, status)
                .eq(StarQuoteWay::getIsDelete, NumberCst.ZERO));
    }

    /**
     * 获取主要的活跃平台
     *
     * @return
     */
    private List<String> getPlatformIds() {
        //查询（活跃平台）字典表名称
        List<BaseDicts> dictList = baseInfoClient.getDictList(DictTypeCst.PUBLISHING_PLATFORM).getObj();
        BusinessAssert.notEmpty(dictList, McnErrorCode.DATA_NOT_FOUND, "字典未配置-发布平台(Publishing_platform)");
        return dictList.stream().map(BaseDicts::getDictsCode).collect(Collectors.toList());
    }
}
